package com.immortal.core.module.log.handlers;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>Title: LogHandlerHelp</p>
 * <p>Description: TODO</p>
 *
 * @author xukk
 * @version 1.0
 * @date 2018/7/27
 */
public class LogHandlerHelp {
    private static Map<String, String[]> parameterNameCaches = new ConcurrentHashMap<String, String[]>();
    private static Map<String, Expression> spelExpressionCaches = new ConcurrentHashMap<String, Expression>();
    private static ExpressionParser parser = new SpelExpressionParser();
    private static LocalVariableTableParameterNameDiscoverer parameterNameDiscovere =
            new LocalVariableTableParameterNameDiscoverer();
    /**
     * 解析执行模板。
     *
     * @param template
     * @param joinPoint
     * @return
     */
    public static String executeTemplate(String template,JoinPoint joinPoint) {
        // get method parameter name
        String methodLongName = joinPoint.getSignature().toLongString();
        String[] parameterNames =  parameterNameCaches.get(methodLongName);
        Method method=null;
        if(parameterNames == null) {
            method = ((MethodSignature) joinPoint.getSignature()).getMethod();
            parameterNames = parameterNameDiscovere.getParameterNames(method);

            parameterNameCaches.put(methodLongName, parameterNames);
        }
        // add args to expression context
        ExpressionRootObject rootObject=new ExpressionRootObject(method,joinPoint.getArgs(),joinPoint.getTarget(),joinPoint.getTarget().getClass());
        MethodBasedEvaluationContext context = new MethodBasedEvaluationContext(rootObject, method,joinPoint.getArgs(), parameterNameDiscovere);
        Object[] args = joinPoint.getArgs();
        if(args.length == parameterNames.length) {
            for(int i=0, len=args.length; i<len; i++){

                context.setVariable(parameterNames[i], args[i]);
            }
        }
        //cacha expression
        Expression expression = spelExpressionCaches.get(template);
        if(expression == null) {
            expression = parser.parseExpression(template, new TemplateParserContext());
            spelExpressionCaches.put(template, expression);
        }
        String value = expression.getValue(context, String.class);
        return value;
    }
    public static Boolean isConditionPassing(JoinPoint joinPoint, String condition) {
        Method method = getMethod(joinPoint);
        ExpressionRootObject rootObject = new ExpressionRootObject(method, joinPoint.getArgs(), joinPoint.getTarget(), joinPoint.getTarget().getClass());
        EvaluationContext context = new MethodBasedEvaluationContext(rootObject, method, joinPoint.getArgs(), parameterNameDiscovere);
        return parser.parseExpression(condition).getValue(context, Boolean.class);
    }
    private static Method getMethod(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        if (method.getDeclaringClass().isInterface()) {
            try {
                method = joinPoint.getTarget().getClass().getDeclaredMethod(signature.getName(),
                        method.getParameterTypes());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return method;
    }
}
